package com.wangjiacai.utils.utils;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class FileUtil {

    /*
     * 获取文件后缀
     */
    public static String getFileExt(String fileName) {
        int dotIndex = fileName.lastIndexOf(".");
        String fileExt = fileName.substring(dotIndex + 1);
        return fileExt;
    }

    /*
     * 获取文件名
     */
    public static String getFileName(String path) {
        int index1 = path.lastIndexOf("/");
        int index2 = path.lastIndexOf(".");
        String fileName = path.substring(index1 + 1, index2);
        return fileName;
    }

    /*
     * 获取父文件路径
     */
    public static String getParentFilePath(String path) {
        int index = path.lastIndexOf("/");
        return path.substring(0, index);
    }

    /**
     * 删除文件夹里面的所有文件
     *
     * @param path 文件夹路径 如 c:/fqf
     */
    public static void delAllFile(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
        if (!file.isDirectory()) {
            return;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
                delFolder(path + "/" + tempList[i]);// 再删除空文件夹
            }
        }
    }

    /**
     * 删除文件夹
     *
     * @param folderPath 文件夹路径及名称 如c:/fqf
     */
    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); // 删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            myFilePath.delete(); // 删除空文件夹

        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * 复制单个文件
     *
     * @param oldPath 源文件路径
     * @param newPath 复制后路径
     * @return 文件大小
     */
    public static int copyFile(String oldPath, String newPath) {
        try {
            int bytesum = 0;
            int byteread = 0;
            File oldfile = new File(oldPath);
            if (oldfile.exists()) {
                InputStream inStream = new FileInputStream(oldPath); // 读入原文件
                FileOutputStream fs = new FileOutputStream(newPath);
                byte[] buffer = new byte[1444];
                int length;
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; // 字节数 文件大小
                    System.out.println(bytesum);
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
                fs.close();
            }
            return bytesum;
        } catch (Exception e) {
            System.out.println("复制单个文件操作出错");
            e.printStackTrace();
            return 0;
        }
    }

    public static void copyStream(InputStream in,OutputStream out) throws IOException {
        int len;
        byte [] buf = new byte[1024];
        while ((len = in.read(buf)) != -1){
            out.write(buf, 0, len);
        }
    }
    /**
     * 复制文件流到新的文件
     *
     * @param inStream 文件流
     * @param file     新文件
     * @return 是否复制成功
     */
    public static boolean copyInputStreamToFile(final InputStream inStream, File file) throws IOException {
        int bytesum = 0;
        int byteread = 0;
        byte[] buffer = new byte[1024];
        FileOutputStream fs = new FileOutputStream(file);
        while ((byteread = inStream.read(buffer)) != -1) {
            bytesum += byteread; // 字节数 文件大小
            fs.write(buffer, 0, byteread);
        }
        inStream.close();
        fs.close();
        return true;
    }

    /**
     * 删除指定路径下的文件
     *
     * @param filePathAndName 文件路径
     */
    public static void delFile(String filePathAndName) {
        try {
            File myDelFile = new File(filePathAndName);
            myDelFile.delete();
        } catch (Exception e) {
            System.out.println("删除文件操作出错");
            e.printStackTrace();
        }
    }


    public static File copyToFile(MultipartFile multipartFile, String parentUrl) throws IOException {
        File parentFile = new File(parentUrl);
        if (!parentFile.exists()) parentFile.mkdirs();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String filename = format.format(new Date()) + RandomStringUtils.randomNumeric(5) + "." + getFileExt(multipartFile.getOriginalFilename());
        File file = new File(parentFile, filename);
        multipartFile.transferTo(file);
        return file;
    }

    public static String randomFileName(String path) {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String filename = format.format(new Date()) + RandomStringUtils.randomNumeric(5) + "." + getFileExt(path);
        return filename;
    }

    public static void listDirectory(File directory) {
        System.out.println(directory.getAbsolutePath());
        if (!directory.isDirectory()) return;
        if (directory.listFiles() != null) {
            for (File file : directory.listFiles()) {
                if (file.isFile()) {
                    System.out.println(file.getAbsolutePath());
                } else {
                    listDirectory(file);
                }
            }
        }
    }

    public static void listAllFile() {
        File[] files = File.listRoots();
        for (File file : files) {
            if (file.isDirectory()) {
                listDirectory(file);
            } else {
                System.out.println(file.getAbsolutePath());
            }

        }
    }

    public static void createFile(String fileName) {
        File file = new File(fileName);
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void createFile(File file) {
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void createFiles(File... files) {
        try {
            for (File file : files) {
                if (!file.exists()) {
                    file.createNewFile();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void unZip(File file, String targetPath, boolean rename, BiConsumer<String, File> consumer) throws Exception {
        File pathFile = new File(targetPath);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        String fileEncode = EncodeUtil.getEncode(file, true);
        ZipFile zipFile = new ZipFile(file, Charset.forName(fileEncode));
        Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
        while (enumeration.hasMoreElements()) {
            ZipEntry zipEntry = enumeration.nextElement();
            String zipName = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                new File(pathFile, zipName).mkdirs();
                continue;
            }
            String filename;
            if (rename) {
                SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
                int index = zipName.lastIndexOf("/");
                if (index != -1) {
                    filename = zipName.substring(0, index) + "/" + format.format(new Date()) + RandomStringUtils.randomNumeric(5) + "." + getFileExt(zipName);
                } else
                    filename = format.format(new Date()) + RandomStringUtils.randomNumeric(5) + "." + getFileExt(zipName);
            } else filename = zipName;
            File targetFile = new File(pathFile, filename);
            try {
                FileUtil.copyInputStreamToFile(zipFile.getInputStream(zipEntry), targetFile);
                if (consumer != null) consumer.accept(zipName, targetFile);
            } catch (Exception e) {
                if (e instanceof FileNotFoundException) continue;
                e.printStackTrace();
            }
        }
        zipFile.close();
    }

    public static void unZip(File file, String targetPath, BiConsumer<String, InputStream> consumer) {
        try {
            File pathFile = new File(targetPath);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            String fileEncode = EncodeUtil.getEncode(file, true);
            ZipFile zipFile = new ZipFile(file, Charset.forName(fileEncode));
            Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
            while (enumeration.hasMoreElements()) {
                ZipEntry zipEntry = enumeration.nextElement();
                String zipName = zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    new File(pathFile, zipName).mkdirs();
                    continue;
                }
                if (consumer != null) consumer.accept(zipName, zipFile.getInputStream(zipEntry));
            }
            zipFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void unZipConsumerAbsolutePath(File file, String targetPath, BiConsumer<String, InputStream> consumer) {
        try {
            File pathFile = new File(targetPath);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            String fileEncode = EncodeUtil.getEncode(file, true);
            ZipFile zipFile = new ZipFile(file, Charset.forName(fileEncode));
            Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
            while (enumeration.hasMoreElements()) {
                ZipEntry zipEntry = enumeration.nextElement();
                String zipName = zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    new File(pathFile, zipName).mkdirs();
                    continue;
                }
                if (consumer != null)
                    consumer.accept(pathFile + File.separator + zipName, zipFile.getInputStream(zipEntry));
            }
            zipFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void zip(List<File> list, OutputStream outputStream) throws Exception {
        zip(list, outputStream, null);
    }

    public static void zip(List<File> list, OutputStream outputStream, Consumer<File> consumer) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        for (File file : list) {
            ZipEntry zipEntry = new ZipEntry(getFileName(file.getName()) + "." + getFileExt(file.getName()));
            zipEntry.setSize(file.length());
            zipEntry.setTime(file.lastModified());
            zipOutputStream.putNextEntry(zipEntry);
            copyStream(new FileInputStream(file), zipOutputStream);
            if (consumer != null){
                consumer.accept(file);
            }
        }
        zipOutputStream.close();
    }

    private static void zipDir(ZipOutputStream zipOutputStream, File path, String dir, Consumer<File> consumer) throws Exception {
        File[] list = path.listFiles();
        for (File file : list) {
            String fileName = StringUtils.isEmpty(dir) ? file.getName() : dir + File.separator + file.getName();
            if (file.isDirectory()) {
                zipDir(zipOutputStream, file, fileName, consumer);
            } else {
                ZipEntry zipEntry = new ZipEntry(fileName);
                zipOutputStream.putNextEntry(zipEntry);
                copyStream(new FileInputStream(file), zipOutputStream);
                if (consumer != null) {
                    consumer.accept(file);
                }
            }
        }
    }

    public static void zipDir(String path, OutputStream outputStream, Consumer<File> consumer) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        zipDir(zipOutputStream, new File(path), "", consumer);
        zipOutputStream.close();
    }

    public static void zipDir(File file, OutputStream outputStream, Consumer<File> consumer) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        zipDir(zipOutputStream, file, "", consumer);
        zipOutputStream.close();
    }

    public static void zipDir(String path, String target, Consumer<File> consumer) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(target));
        zipDir(zipOutputStream, new File(path), "", consumer);
        zipOutputStream.close();
    }

    public static void zipDir(File file, String target, Consumer<File> consumer) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(target));
        zipDir(zipOutputStream, file, "", consumer);
        zipOutputStream.close();
    }

    public static void zipDir(String path, OutputStream outputStream) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        zipDir(zipOutputStream, new File(path), "", null);
        zipOutputStream.close();
    }

    public static void zipDir(File file, OutputStream outputStream) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        zipDir(zipOutputStream, file, "", null);
        zipOutputStream.close();
    }

    public static void zipDir(String path, String target) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(target));
        zipDir(zipOutputStream, new File(path), "", null);
        zipOutputStream.close();
    }

    public static void zipDir(File file, String target) throws Exception {
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(target));
        zipDir(zipOutputStream, file, "", null);
        zipOutputStream.close();
    }

    public static ResponseEntity<byte[]> getResponseEntity(String path) throws IOException {
        File file = new File(path);
        return getResponseEntity(FileCopyUtils.copyToByteArray(file), FileUtil.getFileName(path) + "." + FileUtil.getFileExt(path));
    }

    public static ResponseEntity<byte[]> getGetResponseEntity(byte[] bytes, String fileName) throws IOException {
        return getResponseEntity(bytes, new String(fileName.getBytes("utf-8"), "iso-8859-1"));
    }

    public static ResponseEntity<byte[]> getAjaxResponseEntity(byte[] bytes, String srcFileName) throws IOException {
        return getResponseEntity(bytes, URLEncoder.encode(srcFileName, "utf-8"));
    }

    private static ResponseEntity<byte[]> getResponseEntity(byte[] bytes, String fileName) throws IOException {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentDispositionFormData("attachment", fileName);
        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.CREATED);
    }

}
